﻿using System.Windows;
using System.Windows.Controls;

namespace Utils.Wpf
{
	// Taken from here: http://blog.functionalfun.net/2008/06/wpf-passwordbox-and-data-binding.html
	public static class PasswordBoxAssistant
	{
		public static readonly DependencyProperty BoundPassword = DependencyProperty.RegisterAttached("BoundPassword", typeof(string), typeof(PasswordBoxAssistant), new PropertyMetadata(string.Empty, OnBoundPasswordChanged));

		public static readonly DependencyProperty BindPassword = DependencyProperty.RegisterAttached("BindPassword", typeof(bool), typeof(PasswordBoxAssistant), new PropertyMetadata(false, OnBindPasswordChanged));

		private static readonly DependencyProperty UpdatingPassword = DependencyProperty.RegisterAttached("UpdatingPassword", typeof(bool), typeof(PasswordBoxAssistant), new PropertyMetadata(false));

		private static void OnBoundPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			PasswordBox box = d as PasswordBox;

			// Only handle this event when the property is attached to a PasswordBox and when the BindPassword attached property has been set to true
			if (box != null && PasswordBoxAssistant.GetBindPassword(box))
			{
				// Avoid recursive updating by ignoring the box's changed event
				box.PasswordChanged -= PasswordBoxAssistant.HandlePasswordChanged;

				string newPassword = (string)e.NewValue;

				if (!PasswordBoxAssistant.GetUpdatingPassword(box))
				{
					box.Password = newPassword;
				}

				box.PasswordChanged += PasswordBoxAssistant.HandlePasswordChanged;
			}
		}

		private static void OnBindPasswordChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
		{
			// When the BindPassword attached property is set on a PasswordBox, start listening to its PasswordChanged event

			PasswordBox box = dp as PasswordBox;

			if (box != null)
			{
				bool wasBound = (bool)(e.OldValue);
				bool needToBind = (bool)(e.NewValue);

				if (wasBound)
				{
					box.PasswordChanged -= PasswordBoxAssistant.HandlePasswordChanged;
				}

				if (needToBind)
				{
					box.PasswordChanged += PasswordBoxAssistant.HandlePasswordChanged;
				}

			}
		}

		private static void HandlePasswordChanged(object sender, RoutedEventArgs e)
		{
			PasswordBox box = sender as PasswordBox;

			if (box != null)
			{
				PasswordBoxAssistant.SetUpdatingPassword(box, true);
				PasswordBoxAssistant.SetBoundPassword(box, box.Password);
				PasswordBoxAssistant.SetUpdatingPassword(box, false);
			}
		}

		public static void SetBindPassword(DependencyObject dp, bool value)
		{
			dp.SetValue(PasswordBoxAssistant.BindPassword, value);
		}

		public static bool GetBindPassword(DependencyObject dp)
		{
			return (bool)dp.GetValue(PasswordBoxAssistant.BindPassword);
		}

		public static string GetBoundPassword(DependencyObject dp)
		{
			return (string)dp.GetValue(PasswordBoxAssistant.BoundPassword);
		}

		public static void SetBoundPassword(DependencyObject dp, string value)
		{
			dp.SetValue(PasswordBoxAssistant.BoundPassword, value);
		}

		private static bool GetUpdatingPassword(DependencyObject dp)
		{
			return (bool)dp.GetValue(PasswordBoxAssistant.UpdatingPassword);
		}

		private static void SetUpdatingPassword(DependencyObject dp, bool value)
		{
			dp.SetValue(PasswordBoxAssistant.UpdatingPassword, value);
		}
	}
}